﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using SBBitmap;
using System.IO;
using ImageControl;
using System.Runtime.InteropServices;

namespace AnnaLiese
{
    public partial class Main:Form
    {   
        private Point cursorPos;
        private int r = 0, g = 0, b = 0;
        //private HistogramWindow histogramWindow = new HistogramWindow();
        private int vorschauLabelCount = 1;
        private int imageRGBLabelCount = 1;
        private String currentImagePath;
        private bool selectingColor = false;
        private Point currMouseCoords;
        private Color selectedColor;
        Matrix2D translationScaleMatrix;
        public Main()
        {
            InitializeComponent();
            
            pictureBox.ImagePortionCopied += new Tpsc.Controls.ImagePortionCopiedEventHandler(pictureBox_BitmapCopiedEvent);
            pictureBox.Paint += new PaintEventHandler(pictureBox_Paint);
            pictureBox.MouseMove += new MouseEventHandler(pictureBox_MouseMove);
            pictureBox.Click += new EventHandler(pictureBox_Click);
            pictureBox.CurrentZoomChanged += new EventHandler(pictureBox_CurrentZoomChanged);
            pictureBox.ScrollPositionChanged += new EventHandler(pictureBox_ScrollPositionChanged);
            pictureBox.MouseWheel += new MouseEventHandler(pictureBox_ScrollPositionChanged);
            translationScaleMatrix = Matrix2D.Identity;
        }

        
        void pictureBox_ScrollPositionChanged(object sender, EventArgs e)
        {
            translationScaleMatrix.Matrix[0, 2] = -pictureBox.HorizontalScroll.Value;
            translationScaleMatrix.Matrix[1, 2] = -pictureBox.VerticalScroll.Value;
            pictureBox.Invalidate(true);
        }

        void pictureBox_CurrentZoomChanged(object sender, EventArgs e)
        {
            translationScaleMatrix.Matrix[0, 0] = pictureBox.CurrentZoom;
            translationScaleMatrix.Matrix[1, 1] = pictureBox.CurrentZoom;
            translationScaleMatrix.Matrix[0, 2] = -pictureBox.HorizontalScroll.Value;
            translationScaleMatrix.Matrix[1, 2] = -pictureBox.VerticalScroll.Value;
            pictureBox.Invalidate(true);

        }

        void pictureBox_Click(object sender, EventArgs e)
        {
            if (selectingColor)
            {
                SBBitmap.WarpBitmap bmp = new WarpBitmap(50, 50, PixelFormat.Format24bppRgb);
                //Color c = GetColorAt(currMouseCoords);
                for (int i = 0; i < 50; i++)
                {
                    for (int j = 0; j < 50; j++)
                    {
                        bmp.SetPixel(j, i, selectedColor);
                    }
                }
                VorschauBox vorschauBox = new VorschauBox(bmp.Image);

                vorschauBox.Margin = new Padding(10);
                vorschauBox.Width = flowLayoutPanel.Width / 3 - 30;
                vorschauBox.Height = flowLayoutPanel.Height - 30;
                //vorschauBox.Image = (e.Image as Bitmap).Clone(new Rectangle(0,0, e.Image.Width, e.Image.Height), PixelFormat.Format24bppRgb);
                vorschauBox.OnDeleting += new VorschauBox.PictureBoxDeleteHandler(vorschauBox_OnDeleting);
                vorschauBox.OnDeletingEverything += new EventHandler(vorschauBox_OnDeletingEverything);
                vorschauBox.OnClick += new VorschauBox.PictureBoxClickHandler(vorschauBox_OnClick);
                //vorschauBox.OnAddHistogram += new VorschauBox.HistogramEventHandler(vorschauBox_OnAddHistogram);
                flowLayoutPanel.Controls.Add(vorschauBox);
                vorschauBox.Label = vorschauLabelCount++.ToString();
                btnCalcResult.Enabled = true;

                btnToList.Enabled = true;
                r = 0; g = 0; b = 0;
                int pixel = 0;
                foreach (var control in flowLayoutPanel.Controls)
                {
                    if (control is VorschauBox)
                    {
                        pixel++;
                        r += (control as VorschauBox).AverageColor.R;
                        g += (control as VorschauBox).AverageColor.G;
                        b += (control as VorschauBox).AverageColor.B;
                    }
                }
                r /= pixel;
                g /= pixel;
                b /= pixel;

                labelRGBall.Text = r + "," + g + "," + b;
                toolStripButtonSelectColor.Checked = false;
                toolStripButton1_Click(sender, e);
            }
        }

        void pictureBox_MouseMove(object sender, MouseEventArgs e)
        {
            if (selectingColor)
            {
                currMouseCoords = e.Location;
                Refresh();
            }
        }

        void pictureBox_Paint(object sender, PaintEventArgs e)
        {
            if (selectingColor)
            {
                try
                {
                    Rectangle rect = new Rectangle(currMouseCoords.X - 20, currMouseCoords.Y - 20, 15, 15);

                    //float multiplier = 1 / pictureBox.CurrentZoom;
                    //int xOffset = -pictureBox.AutoScrollPosition.X;
                    //int yOffset = -pictureBox.AutoScrollPosition.Y;
                    //int dragX = Convert.ToInt32(((float)currMouseCoords.X + xOffset) * multiplier);
                    //int dragY = Convert.ToInt32(((float)currMouseCoords.Y + yOffset) * multiplier);

                    Point mousePoint = (Vector2D) currMouseCoords * translationScaleMatrix.Invert();
                    selectedColor = (pictureBox.backup as Bitmap).GetPixel(mousePoint.X, mousePoint.Y);
                    e.Graphics.FillRectangle(new SolidBrush(selectedColor), rect);
                    e.Graphics.DrawRectangle(Pens.Black, rect);
                    //DEBUG: Text = currMouseCoords.X.ToString() + ":" + currMouseCoords.Y.ToString() + " ->  " + mousePoint.X.ToString() + ":" + mousePoint.Y.ToString();
                }
                catch { }
                
            }
        }


        void pictureBox_BitmapCopiedEvent(object sender, Tpsc.Controls.ImagePortionCopiedEventArgs e)
        {
            VorschauBox vorschauBox = new VorschauBox((e.Image as Bitmap).Clone(new Rectangle(0, 0, e.Image.Width, e.Image.Height), PixelFormat.Format24bppRgb));
            
            vorschauBox.Margin = new Padding(10);
            vorschauBox.Width = flowLayoutPanel.Width / 3 - 30;
            vorschauBox.Height = flowLayoutPanel.Height - 30;
            //vorschauBox.Image = (e.Image as Bitmap).Clone(new Rectangle(0,0, e.Image.Width, e.Image.Height), PixelFormat.Format24bppRgb);
            vorschauBox.OnDeleting += new VorschauBox.PictureBoxDeleteHandler(vorschauBox_OnDeleting);
            vorschauBox.OnDeletingEverything += new EventHandler(vorschauBox_OnDeletingEverything);
            vorschauBox.OnClick += new VorschauBox.PictureBoxClickHandler(vorschauBox_OnClick);
            //vorschauBox.OnAddHistogram += new VorschauBox.HistogramEventHandler(vorschauBox_OnAddHistogram);
            flowLayoutPanel.Controls.Add(vorschauBox);
            vorschauBox.Label = vorschauLabelCount++.ToString();
            btnCalcResult.Enabled = true;
            
            btnToList.Enabled = true;
            r = 0; g = 0; b = 0;
            int pixel = 0;
            foreach (var control in flowLayoutPanel.Controls)
            {
                if (control is VorschauBox)
                {
                    pixel++;
                    r += (control as VorschauBox).AverageColor.R;
                    g += (control as VorschauBox).AverageColor.G;
                    b += (control as VorschauBox).AverageColor.B;
                }
            }
            r /= pixel;
            g /= pixel;
            b /= pixel;

            labelRGBall.Text = r + "," + g + "," + b;
            //e.Image.Save("test.bmp", ImageFormat.Bmp);
        }

        void vorschauBox_OnDeletingEverything(object sender, EventArgs e)
        {
            flowLayoutPanel.Controls.Clear();
            btnToList.Enabled = false;
            //btnCalcResult.Enabled = false;
            labelRGBall.Text = "0,0,0";
            labelRGB.Text = "0,0,0";
            labelWidth.Text = "0";
            labelHeight.Text = "0";
        }

        void vorschauBox_OnClick(object sender, ImageEventArgs e)
        {
            foreach (var element in flowLayoutPanel.Controls)
            {
                if (sender != element)
                {
                    (element as VorschauBox).BackColor = SystemColors.GradientActiveCaption;
                }
            }
            labelWidth.Text = e.Width.ToString();
            labelHeight.Text = e.Height.ToString();
            labelRGB.Text = e.RGB.R + "," + e.RGB.G + "," + e.RGB.B;
        }

        void vorschauBox_OnDeleting(object sender, EventArgs e)
        {
            if (flowLayoutPanel.Controls.Contains(sender as VorschauBox))
            {
                flowLayoutPanel.Controls.Remove(sender as VorschauBox);
                if (flowLayoutPanel.Controls.Count == 0)
                {
                    //btnCalcResult.Enabled = false;
                    btnToList.Enabled = false;
                    labelRGBall.Text = "0,0,0";
                }
                else
                {
                    r = 0; g = 0; b = 0;
                    int pixel = 0;
                    foreach (var control in flowLayoutPanel.Controls)
                    {
                        if (control is VorschauBox)
                        {
                            pixel++;
                            r += (control as VorschauBox).AverageColor.R;
                            g += (control as VorschauBox).AverageColor.G;
                            b += (control as VorschauBox).AverageColor.B;
                        }
                    }
                    r /= pixel;
                    g /= pixel;
                    b /= pixel;

                    labelRGBall.Text = r + "," + g + "," + b;

                    
                }
                labelRGB.Text = "0,0,0";
                labelWidth.Text = "0";
                labelHeight.Text = "0";
            }
        }

       


        private void menuDateiOeffnen_Click(object sender, EventArgs e)
        {
            if (openFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {

                foreach (String fileName in openFileDialog.FileNames)
                {
                    PreviewImage imgControl = new PreviewImage();
                    imgControl.Image = new Bitmap(fileName);
                    imgControl.OnDeleting += new EventHandler(imgControl_OnDeleting);
                    imgControl.OnClick += new EventHandler(imgControl_OnClick);
                    imgControl.OnDeletingEverything += new EventHandler(imgControl_OnDeletingEverything);
                    FileInfo fi = new FileInfo(fileName);
                    imgControl.Label = fi.Name;
                    currentImagePath = imgControl.Label;
                    flowLayoutPanelPicturePreview.Controls.Add(imgControl);
                }
                pictureBox.Image = new Bitmap(openFileDialog.FileName);
                (flowLayoutPanelPicturePreview.Controls[0] as PreviewImage).BorderStyle = BorderStyle.Fixed3D;
            }
        }

        void imgControl_OnClick(object sender, EventArgs e)
        {
            pictureBox.Image = (sender as PreviewImage).Image;
            foreach (PreviewImage element in flowLayoutPanelPicturePreview.Controls)
            {
                element.BorderStyle = BorderStyle.FixedSingle;
            }
            (sender as PreviewImage).BorderStyle = BorderStyle.Fixed3D;
            currentImagePath = (sender as PreviewImage).Label;
        }


        void imgControl_OnDeletingEverything(object sender, EventArgs e)
        {
            flowLayoutPanelPicturePreview.Controls.Clear();
        }

        void imgControl_OnDeleting(object sender, EventArgs e)
        {
            (sender as PreviewImage).Dispose();
        }



        private void pictureBox_MouseDown(object sender, MouseEventArgs e)
        {
            cursorPos = e.Location;
        }

        private void btnSaveResult_Click(object sender, EventArgs e)
        {
            if (saveFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                try
                {
                    pictureBoxResult.Image.Save(saveFileDialog.FileName);
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Fehler beim Speichern des Bildes. Evtl fehlen die Zugriffsrechte\n" + ex.Message, "Fehler");
                }
            }
        }

        public int getIndexByColor(Color pixelcolor)
        {
            byte r, g, b;

            r = pixelcolor.R;
            g = pixelcolor.G;
            b = pixelcolor.B;

            return (int)(b + g * Math.Pow(256, 1) + r * Math.Pow(256, 2));
        }

        public Color getColorByIndex(int index)
        {
            double dval_b, dval_g, dval_r;
            int ival_b, ival_g, ival_r;
            int r, g, b;

            dval_b = (double)index / 256;
            ival_b = index / 256;
            b = index - ival_b * 256;

            dval_g = (double)ival_b / 256;
            ival_g = ival_b / 256;
            g = ival_b - ival_g * 256;

            dval_r = (double)ival_g / 256;
            ival_r = ival_g / 256;
            r = ival_g - ival_r * 256;

            return (Color.FromArgb(r, g, b));
        }

        private void btnToList_Click(object sender, EventArgs e)
        {
            ImageRGB img = new ImageRGB();
            img.OnDeleting += new EventHandler(img_OnDeleting);
            img.OnDeletingEverything += new EventHandler(img_OnDeletingEverything);
            //img.OnAddHistogram += new ImageRGB.HistogramEventHandler(img_OnAddHistogram);
            img.Anchor = AnchorStyles.Left | AnchorStyles.Right;
            img.Image = pictureBox.Image as Bitmap;
            img.RGBValue = r + "," + g + "," + b;
            flowLayoutPanelImages.Controls.Add(img);
            img.Label = currentImagePath;
        }

        void img_OnDeletingEverything(object sender, EventArgs e)
        {
            flowLayoutPanelImages.Controls.Clear();
        }

        void img_OnDeleting(object sender, EventArgs e)
        {
            if (flowLayoutPanelImages.Controls.Contains(sender as ImageRGB))
            {
                flowLayoutPanelImages.Controls.Remove(sender as ImageRGB);
               
            }

        }

        private void Main_SizeChanged(object sender, EventArgs e)
        {
            foreach (VorschauBox element in flowLayoutPanel.Controls)
            {
                element.Width = flowLayoutPanel.Width / 3 - 30;
                element.Height = flowLayoutPanel.Height - 30;
                
            }
        }

        private void copyImageToTemplateToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //Ganzes Bild als neues Template generieren
            VorschauBox vorschauBox = new VorschauBox(new Bitmap(openFileDialog.FileName));

            vorschauBox.Margin = new Padding(10);
            vorschauBox.Width = flowLayoutPanel.Width / 3 - 30;
            vorschauBox.Height = flowLayoutPanel.Height - 30;
            //vorschauBox.Image = (e.Image as Bitmap).Clone(new Rectangle(0,0, e.Image.Width, e.Image.Height), PixelFormat.Format24bppRgb);
            vorschauBox.OnDeleting += new VorschauBox.PictureBoxDeleteHandler(vorschauBox_OnDeleting);
            vorschauBox.OnDeletingEverything += new EventHandler(vorschauBox_OnDeletingEverything);
            vorschauBox.OnClick += new VorschauBox.PictureBoxClickHandler(vorschauBox_OnClick);
            //vorschauBox.OnAddHistogram += new VorschauBox.HistogramEventHandler(vorschauBox_OnAddHistogram);
            flowLayoutPanel.Controls.Add(vorschauBox);
            vorschauBox.Label = vorschauLabelCount++.ToString();
            //btnCalcResult.Enabled = true;

            btnToList.Enabled = true;
            r = 0; g = 0; b = 0;
            int pixel = 0;
            foreach (var control in flowLayoutPanel.Controls)
            {
                if (control is VorschauBox)
                {
                    pixel++;
                    r += (control as VorschauBox).AverageColor.R;
                    g += (control as VorschauBox).AverageColor.G;
                    b += (control as VorschauBox).AverageColor.B;
                }
            }
            r /= pixel;
            g /= pixel;
            b /= pixel;

            labelRGBall.Text = r + "," + g + "," + b;
        }

        private void btnCalcResult_Click(object sender, EventArgs e)
        {
            List<int> AnzFarben = new List<int>();
            int[] AnzFarbenCodiert = new int[256 * 256 * 256];
            int templateWidth, templateHeight, tmp, rest;
            Dictionary<WarpBitmap, bool> TemplateImageList = new Dictionary<WarpBitmap, bool>();
            List<Color> testList = new List<Color>();


            foreach (VorschauBox element in flowLayoutPanel.Controls)
            {
                TemplateImageList.Add(new WarpBitmap(element.Image.Clone() as Bitmap), element.Subtract);

            }
            //Wenn mehr als ein Farbtemplate generiert wurde, zu einem zusammenfassen
            //if (TemplateImageList.Count > 1)
            {
                for (int i = 0; i < TemplateImageList.Count; i++)
                {
                    for (int u = 0; u < TemplateImageList.Keys.ElementAt(i).Height; u++)
                    {
                        for (int v = 0; v < TemplateImageList.Keys.ElementAt(i).Width; v++)
                        {
                            if (!TemplateImageList[TemplateImageList.Keys.ElementAt(i)])
                            {
                                //Alle Farben der Templates werden in diesem Array gezählt
                                AnzFarbenCodiert[getIndexByColor(TemplateImageList.Keys.ElementAt(i).GetPixel(v, u))]++;
                                //if(!testList.Contains(TemplateImageList[i].GetPixel(v, u)))
                                {

                                    testList.Add(TemplateImageList.Keys.ElementAt(i).GetPixel(v, u));
                                }
                            }
                            else
                            {
                                if (AnzFarbenCodiert[getIndexByColor(TemplateImageList.Keys.ElementAt(i).GetPixel(v, u))] > 0)
                                {
                                    AnzFarbenCodiert[getIndexByColor(TemplateImageList.Keys.ElementAt(i).GetPixel(v, u))]--;
                                }
                                if (testList.Contains(TemplateImageList.Keys.ElementAt(i).GetPixel(v, u)))
                                {
                                    testList.Remove(TemplateImageList.Keys.ElementAt(i).GetPixel(v, u));
                                }
                            }
                        }
                    }
                }
                if (testList.Count == 0)
                {
                    return;
                }
                //Nun Zählen wieviele verschiedene Farben in den Templates vorhanden sind:
                for (int i = 0; i < AnzFarbenCodiert.Length; i++)
                {

                    if (AnzFarbenCodiert[i] > 0)
                    {
                        AnzFarben.Add(i);
                    }
                }
                //Template sollte möglichst quadratisch bzw. rechteckig mit ähnlichen Seitenlängen besitzen
                //Dazu für die Länge einer Seite die Wurzel aus der Anzahl setzen
                templateHeight = (int)Math.Sqrt(AnzFarben.Count);
                tmp = AnzFarben.Count / templateHeight;
                if (tmp * templateHeight == AnzFarben.Count)
                    templateWidth = tmp;
                else
                {
                    templateWidth = tmp + 1;
                    rest = templateWidth * templateHeight - AnzFarben.Count;
                }

                //Neues Template erstellen mit der Zusammenfassung aller unterschiedlichen Farben
                //aus den bisher erstellten Templates
                WarpBitmap template = new WarpBitmap(templateWidth, templateHeight, PixelFormat.Format24bppRgb);
                int x = 0;

                for (int i = 0; i < templateHeight; i++)
                {
                    for (int j = 0; j < templateWidth; j++)
                    {
                        if (x < AnzFarben.Count)
                        {
                            template.SetPixel(j, i, getColorByIndex(AnzFarben[x]));
                            x++;
                        }
                        //Wenn bereits alle verschiedenen Farben in das Template
                        //geschrieben wurden, aber aus Gründen der berechneten Templategröße
                        //noch ein paar Pixel mit Farben gesetzt werden müssen, wird
                        //für die restlichen Pixel einfach der letzte Farbwert gesetzt.
                        else
                        {
                            template.SetPixel(j, i, getColorByIndex(AnzFarben[x - 1]));
                        }
                    }
                }
                //Template in TemplateControlListe hinzufügen
                pictureBoxResult.Image = template.Image;

                btnSaveResult.Enabled = true;
            }
        }


        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            if (pictureBox.Image == null)
            {
                toolStripButtonSelectColor.Checked = false;
                return;
            }
            Cursor = (toolStripButtonSelectColor.Checked ? Cursors.Cross : Cursors.Default);
            selectingColor = toolStripButtonSelectColor.Checked;
            if (toolStripButtonSelectColor.Checked)
            {
            }
            Refresh();
        }       
    }

}
